package org.lex.game.sudoku.view.solver;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

import org.lex.game.sudoku.model.solver.Decision;
import org.lex.game.sudoku.model.solver.SolverObserver;

public class TreeSolverObserver extends JTree implements SolverObserver {
	private static final long serialVersionUID = -6848662792476292646L;

	private DefaultTreeModel model = null;
	private MutableTreeNode current = null;

	public TreeSolverObserver() {
		this.initialize();
		this.setRootVisible(false);
	}

	private void initialize() {
		MutableTreeNode root = new DefaultMutableTreeNode("root", true);
		this.current = root;
		this.model = new DefaultTreeModel(root, true);
		this.setModel(model);
	}

	@Override
	public void beginDecision(Decision d) {
		StringBuilder buf = new StringBuilder();
		buf.append("Begin decision at (").append(d.row + 1).append(", ").append(d.column + 1).append(")=?")
				.append(d.number);
		MutableTreeNode node = new DefaultMutableTreeNode(buf.toString(), true);
		model.insertNodeInto(node, this.current, this.current.getChildCount());
		TreePath nodePath = new TreePath(model.getPathToRoot(node));
		this.expandPath(nodePath);
		this.scrollPathToVisible(nodePath);

		this.current = node;
	}

	@Override
	public void fillCell(int row, int col, int num) {
		StringBuilder buf = new StringBuilder();
		buf.append("filled cell (").append(row + 1).append(", ").append(col + 1).append(")=").append(num);
		MutableTreeNode node = new DefaultMutableTreeNode(buf.toString(), false);
		model.insertNodeInto(node, this.current, this.current.getChildCount());
		TreePath nodePath = new TreePath(model.getPathToRoot(node));
		this.expandPath(nodePath);
		this.scrollPathToVisible(nodePath);
	}

	@Override
	public void rollbackDecision(Decision d, int cellCount) {
		StringBuilder buf = new StringBuilder();
		buf.append("Rollback decision at (").append(d.row + 1).append(", ").append(d.column + 1).append(")=?")
				.append(d.number);
		buf.append(", ").append(cellCount).append(" cells rollbacked");
		MutableTreeNode node = new DefaultMutableTreeNode(buf.toString(), false);
		model.insertNodeInto(node, this.current, this.current.getChildCount());
		TreePath nodePath = new TreePath(model.getPathToRoot(this.current));
		this.collapsePath(nodePath);
		this.scrollPathToVisible(nodePath);
		this.current = (MutableTreeNode) this.current.getParent();
	}

	@Override
	public void reset() {
		this.initialize();
	}
}
